﻿namespace EasyWeb.Test
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Reflection;
    using EasyWeb.Design;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class DisplayAttributeResources_Test
    {
        [TestMethod]
        public void All_Test()
        {
            Test(new[] { typeof(EWEntityDefinition) }, typeof(EWEntityDefinitionResources));
            Test(new[] { typeof(EWFieldDefinition) }, typeof(EWFieldDefinitionResources));
            Test(new[] { typeof(EWSelectionDefinition), typeof(EWSelectionItemDefinition) }, typeof(EWSelectionDefinitionResources));
        }

        private static void Test(IEnumerable<Type> targetTypes, Type resourceType)
        {
            var resources = GetResourceNames(resourceType);
            var targets = GetTargetNames(targetTypes);
            foreach (var target in targets)
            {
                if (resources.Any(pair => pair.Key == target))
                {
                    resources[target] = true;
                }
                else
                {
                    Assert.Fail("The resource '{0}' does not exist.", target);
                }
            }

            Assert.IsFalse(resources.Any(pair => !pair.Value));
        }

        private static IDictionary<string, bool> GetResourceNames(Type type)
        {
            var result = new Dictionary<string, bool>();

            var names = type.GetTypeInfo()
                .GetProperties(BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Static)
                .Where(property => property.PropertyType == typeof(string))
                .Select(property => property.Name);
            foreach (var name in names)
            {
                result.Add(name, false);
            }

            return result;
        }

        private static IEnumerable<string> GetTargetNames(IEnumerable<Type> types)
        {
            return types.SelectMany(targetType =>
            {
                var result = new List<string>();

                var allTypes = targetType.GetTypeInfo()
                    .Assembly
                    .GetTypes()
                    .Where(t => targetType.GetTypeInfo().IsAssignableFrom(t));

                foreach (var type in allTypes)
                {
                    var displayNameAttribute = type.GetTypeInfo().GetCustomAttribute<EWDisplayNameAttribute>(true);
                    if (displayNameAttribute != null)
                    {
                        result.Add(displayNameAttribute.Name);
                    }

                    result.AddRange(type.GetTypeInfo()
                        .GetProperties(BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.Public)
                        .Where(property => property.GetCustomAttribute<DisplayAttribute>(true) != null)
                        .Select(property => property.GetCustomAttribute<DisplayAttribute>(true).Name));
                }

                return result;
            });
        }
    }
}
